using System;


namespace ScienceNET.Optimization
{


    [Flags]
    public enum ComputeEnum
    {
        FunctionValue = 1,
        Gradient = 2,
        Hessian = 4
    }

    public interface IOpimizable
    {
        int ParametersNumber { get;}
        ComputeEnum AllowedComputations { get;}
        void Compute(ComputeEnum compute, IOptimizer optimizer);
    }


    public interface IOptimizer
    {
        double[] Parameters { get;}
        double[] Gradient { get;}
        double[,] Hessian { get;}
        double FunctionValue { get;set;}
    }

    public abstract class OptimizerBase : IOptimizer
    {
        protected int parametersNumber;
        protected IOpimizable optimizedObject;
        protected int epoch = 1;
        protected int show = 1;
        public int EpochsNumber = 50;
        public int MaxTime = 0;
        protected double[] parameters;
        protected double[] gradient;
        protected double[,] hessian;
        protected double functionValue;
        public double[] Parameters { get { return this.parameters; } }
        public double[] Gradient { get { return this.gradient; } }
        public double[,] Hessian { get { return this.hessian; } }
        public double FunctionValue
        {
            get { return this.functionValue; }
            set { this.functionValue = value; }
        }



        public abstract void Step();

        /// <summary>
        /// Realizes optimzation.
        /// </summary>
        public void Optimize()
        {

            for (int epoch = 1; epoch <= EpochsNumber; epoch++)
            {
                this.Step();

                if (show != 0 && epoch % show == 0)
                {
                    Console.Write("{0,5}", epoch);
                    Console.Write(" {0:E8}", functionValue);
                    Console.WriteLine();
                }
            }
        }
    }





 

}